/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	Geometry.h
*
*	Description -	The Geometry class will contain the actual index and vertex buffers.
*					This also contains the Shader-InputLayout mappings.
*
*	Comments	-	Another layer will be on top of this class which will contain the
*					Material-GeometrySubset mapping.
*
*	Modification History:
*			Name			   Date					Description
*			MrCodeSushi	-	09/05/2012	-	Creation of this file
**************************************************************************************/
#ifndef _PSX_MESH_H_
#define _PSX_MESH_H_

#include "PulseSTD.h"
#include "ResourcePoolItem.h"
#include "StoragePool.h"
#include "GraphicsTypes.h"
#include "Effect.h"
#include "InputLayout.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Map.h"
#include "Array.h"
#include "VertexSource.h"
#include "IndexSource.h"

namespace Pulse
{
	struct GeometrySubset
	{
		// We don't pair the material here. Materials are bound in Models.
		UINT32 m_indicesOffset;
		UINT32 m_numPrimitives; // Primitives so that it can be number of triangles, triangle fans, lines, points, etc...
	};

	struct GeometryDesc : public BaseResDesc
	{
	public:
		GeometryDesc( void );

		GeometryDesc( const CHAR *pFilename );

		~GeometryDesc( void );

		// NOTE: For manually creating Geometry.
		//			This may not be needed.
		//void SetGeometry( ETopology::Type topology, VertexBuffer*pVB, IndexBuffer *pIB,
		//	UINT numGeoSubsets, GeometrySubset *pSubsets, EPipelineExecutor::Type executor = EPipelineExecutor::DEFAULT );

		//void AddGeometrySubset(  );

		const BOOL IsStreamSourcesManaged( void ) const { return m_bManageStreamSources; }

		void SetToLoad( const CHAR *pFilename ) { m_filename = pFilename; }

		const CHAR * GetFilename( void ) const { return m_filename.GetBuffer(); }

		// Manual Creation of Geometry
		EErrorCode::Type AddVertexSourceType( EVertexElement::Type type, SIZE_T32 numElements );
		
		EErrorCode::Type AddIndexSource( SIZE_T32 numIndices );

		VertexSource * GetVertexSource( EVertexElement::Type type );
		
		const VertexSource * GetVertexSource( EVertexElement::Type type ) const;

		IndexSource * GetIndexSource( void ) { return m_pIndexSource; }

		virtual const ResourceCode GetType( void ) const { return ResourceCode(EResource::VIDEO, EVideoResource::GEOMETRY); }

		void AddGeometrySubset( UINT32 numPrimitives, UINT32 indicesOffset = 0 );

		const SIZE_T GetNumGeometrySubsets( void ) const { return m_geometrySubsets.GetSize(); }
	
		const GeometrySubset * GetGeometrySubset( UPOS_T i ) { return &m_geometrySubsets[i]; }
	
		const ETopology::Type GetTopology( void ) const { return m_topologyType; }

		// Hack fix see m_bManageStreamSources
		//GeometryDesc & operator = ( GeometryDesc &rhs );

	private:

		void Cleanup( void );

		// Called by the Geometry class to delete the vertex and index sources
		//	when it gets destroyed.
		void SetManageStreamSource( BOOL bManage ) { m_bManageStreamSources = bManage; }

	private:

		// Only called by the constructors...
		void ConstructorDefaultParams( void );

	private:

		friend Geometry;

		typedef Array<GeometrySubset> GeometrySubsetList;
		typedef Array<VertexSource*> VertexSourceList;

		ETopology::Type			m_topologyType;
		GeometrySubsetList		m_geometrySubsets;

		String					m_filename;

		BOOL					m_bManageStreamSources;

		VertexSourceList		m_vertexSources;
		IndexSource				*m_pIndexSource;

	};


	struct RenderPassRenderInfo
	{
		RenderPassRenderInfo( void );
		
		~RenderPassRenderInfo( void );

		typedef Array<VertexBuffer *> VertexBufferList;
	
		InputLayout *m_pInputLayout;
		VertexBufferList m_vertexBuffers; // vertex buffers index position maps to the input layout
	};

	struct TechGeoRenderInfo
	{
		TechGeoRenderInfo( void );

		~TechGeoRenderInfo( void );

		typedef Array< RenderPassRenderInfo* > RenerPassRenderInfoList;
		String m_techniqueName;
		RenerPassRenderInfoList m_renderPassInfos;
	};

	class Geometry : public IResourcePoolItem
	{
	public:

		virtual ~Geometry( void );

		// These defines the base interface for all derived resources
		virtual BOOL CreateResource( BaseResDesc *pDesc );
		virtual BOOL DestroyResource( void );
		virtual BOOL LoadResource( void );
		virtual BOOL UnloadResource( void );

		virtual const ResourceCode GetType( void ) const { return ResourceCode(EResource::VIDEO, EVideoResource::GEOMETRY); }

		const GeometryDesc * GetDesc( void ) const { return &m_desc; }
	
	public:

		const SIZE_T GetNumSubGeometries( void ) const { return m_desc.GetNumGeometrySubsets(); }

		const GeometrySubset * GetGeometrySubset( UPOS_T index );
		
		// Lazy evaluate and create the vertex buffer if needed
		VertexBuffer * GetVertexBuffer( EVertexElement::Type type );

		BOOL IsVertexElementAvailable( EVertexElement::Type type );

		/*InputLayout * GetInputLayout( Effect *pEffect );

		InputLayout * GetInputLayout( RenderTechnique *pTech );*/

		TechGeoRenderInfo * GetTechniqueRenderInfo( RenderTechnique *pTech );

		TechGeoRenderInfo * FindTechniqueRenderInfo( const CHAR *pTechName );

		// Lazy creation of index buffer
		IndexBuffer * GetIndexBuffer( void );

		const ETopology::Type GetTopology( void ) const { return m_desc.GetTopology(); }
	
	private:

		Geometry( void );

		EErrorCode::Type Initialize( void );

		void Cleanup( void );

		// This is not used in replacement to the new method GetVertexBuffer.
		EErrorCode::Type CreateGraphicsBuffers( void );

		TechGeoRenderInfo * CreateTechGeoRenderInfo( RenderTechnique *pTech );

	private:

		// Geometry file processing methods
		EErrorCode::Type ProcessGeometry( XMLElementPtr pElem );

		EErrorCode::Type ProcessInfo( XMLElementPtr pElem );

		EErrorCode::Type ProcessVertexStream( XMLElementPtr pElem );

		EErrorCode::Type ProcessIndexStream( XMLElementPtr pElem );

		EErrorCode::Type ProcessSubGeometryStream( XMLElementPtr pElem );

	private:

		PSX_MakeStoragePoolFriend( Geometry );

		struct VertexTypeBufferPair
		{
			EVertexElement::Type	m_type;
			VertexBuffer			*m_pVertexBuffer;
		};

		typedef Map<EVertexElement::Type, VertexBuffer*>  VertexTypeBufferMap;
		typedef Array<TechGeoRenderInfo*> TechGeoRenderInfoList;

		GeometryDesc				m_desc;
		TechGeoRenderInfoList		m_techRenderInfos;
		VertexTypeBufferMap			m_vertexTypeBufferMap;
		IndexBuffer					*m_pIndexBuffer;

	};
}

#endif /* _PSX_MESH_H_ */